<?php

/*
Plugin to get data from Google Refine to display edit history on a Google Refine "Project"
*/

require_once( config_get( 'core_path' ) . 'bugnote_api.php');
require_once( config_get( 'plugin_path' ) . 'DataRefine' . DIRECTORY_SEPARATOR . 'ProjectsMetadata.php' );
require_once( config_get( 'plugin_path' ) . 'DataRefine' . DIRECTORY_SEPARATOR . 'TableMetadata.php' );
require_once( config_get( 'plugin_path' ) . 'DataRefine' . DIRECTORY_SEPARATOR . 'JSONstore.php' );


/**
 * RefineHistory Class
 */
class DataRefinePlugin extends MantisPlugin {
    
    public $history; //google refine project edit history, false if no project
    public $projectID; //id for google refine project
    public $projectMeta; //google refine project metadata
    public $projectURI; //link to google refine project
    
    public $bugID; //current BugId
    public $bugStatus; //current bug status
    public $bugResolved; //boolean, current bug resolved or not
    
    public $statusResolved = array("resolved", "closed"); //status levels required for marking Google Refine edit issue as completed

    const authHashPrefix = "your hash-salt here, keep same as in Google Refine reverse proxy authentication"; //prefix appended to session id to authorize user for Google Refine.
    const refineBaseURI ="base url of google refine, no final slash"; //uri of google refine. Scan for this 
    const refineLocalURI = "http://127.0.0.1:3333"; // uri of google refine at local server. use FALSE if connecting to remote server.
    const maxShow = 2; //maximum number of edits to show


    /**
     *  A method that populates the plugin information and minimum requirements.
     */
    function register( ) {
        $this->name = "Data Refine";
        $this->description = "Synchs with Google Refine to help manage and track edits / clean-ups of data tables.";
        $this->page = '';

        $this->version = '1.0';
        $this->requires = array(
                'MantisCore' => '1.2.0'
        );

        $this->author = 'Eric Kansa';
        $this->contact = 'ekansa@alexandriaarchive.org';
        $this->url = 'http://ux.opencontext.org/blog/';
    }//end function


    //get some configuration data
    function config() {
        return array(
                'refineBaseURI' => self::refineBaseURI,
		'refineLocalURI' => self::refineLocalURI,
                'authHashPrefix' => self::authHashPrefix
        );
    }//end function

    /**
    * Default plugin configuration.
    */
   function hooks( ) {
        $hooks = array(
	    'EVENT_LAYOUT_RESOURCES' => 'link_js_css',
            'EVENT_MENU_MAIN' => 'refine_ready_menu',
            'EVENT_VIEW_BUG_DETAILS' => 'check_description',
            'EVENT_VIEW_BUGNOTES_START' => array('check_notes', 'display_history')
        );
        return $hooks;
   }//end function
  
  
    function link_js_css(){
	
	$t_plugin_path = "..". DIRECTORY_SEPARATOR. "plugins". DIRECTORY_SEPARATOR;
	$jsPath = $t_plugin_path . 'DataRefine' . DIRECTORY_SEPARATOR . 'js'. DIRECTORY_SEPARATOR;
	$cssPath = $t_plugin_path . 'DataRefine' . DIRECTORY_SEPARATOR . 'css'. DIRECTORY_SEPARATOR;
	$output = "";
	$output .= '<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true" ></script>'.chr(13);
	$output .= '<link rel="stylesheet" type="text/css" href="'.$cssPath.'dataDoc.css" />'.chr(13);
	$output .= '<script type="text/javascript" src="'.$jsPath.'prototype-1.6.0.3.js" /> </script>'.chr(13);
	$output .= '<script type="text/javascript" src="'.$jsPath.'json2.js"> </script>'.chr(13);
	$output .= '<script type="text/javascript" src="'.$jsPath.'ajax_funcs.js" /> </script>'.chr(13);
	$output .= '<script type="text/javascript" src="'.$jsPath.'dataDoc.js" /> </script>'.chr(13);
	$output .= '<link href="'.$cssPath.'tabber.css" rel="stylesheet" type="text/css"/>'.chr(13);
	$output .= '<script type="text/javascript" src="'.$jsPath.'tabber.js"> </script>'.chr(13);
	
	$output .= '
	<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dijit/themes/claro/claro.css"/>
	<script type="text/javascript">
	    dojo.require("dijit.layout.TabContainer");
	    dojo.require("dijit.layout.ContentPane");
	    dojo.require("dojox.layout.FloatingPane");
	</script>
	<style type="text/css">
            @import "http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojox/layout/resources/FloatingPane.css";
            @import "http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojox/layout/resources/ResizeHandle.css";
        </style>
	
	';
	
	return $output;
    }
  
  
    function refine_ready_menu( ) {
	$datasetsHub = plugin_page( 'data-doc-projects' );
	return array( '<a href="' . self::refineBaseURI . '">' . 'Refine (Dataset Edit)' . '</a>',
		     '<a href="' . $datasetsHub . '">' . 'Dataset Tracking' . '</a>'
		     );
    }
    
    
    //look for links to Google Refine in the Desciption of a Bug / Issue
    function check_description($event, $bugID){
        
        global $tpl_description; //gets description string for the bug
	global $tpl_status ; //gets the current status level for a bug
	
        $note = $tpl_description;
        $bugStatus = $tpl_status; //current status of the bug
	if(in_array($bugStatus, $this->statusResolved)){
	    $this->bugResolved = true;
	}
	else{
	    $this->bugResolved = false;
	}


	$this->bugStatus = $bugStatus;
	
        $this->bugID = $bugID;
        $this->history = false;
        $this->projectMeta = false;
        
        $uriPattern = self::refineBaseURI;
        if(stristr($note, $uriPattern)){
            $link = $this->get_link($note);
            if($link != false){
                $history = $this->getHistory($link);
                if($history != false){
                    $this->get_gRefine_metadata();
                }
                $this->history = $history;
		$this->note_bug($bugID); //check to see if this bug needs to be added to the data documentation, if so, it is added.
            }
        }
        
    }


    function note_bug($bugID){
	//this checks to see if a bug needs to be added to documentation for a dataset
	$tableMetaObj = new TableMetadata;
	$tableMetaObj->GRprojectID = $this->projectID;
	$tableMetaObj->get_metadata();
	if(is_array($tableMetaObj->currentMetadata)){
	    //this project is being tracked for data documentation.
	    $tableMetaObj->check_updateIssue($bugID, $this->bugResolved);
	}
    }
    



    function check_notes($event, $bugID, $BugNotes){
        
        if(!is_array($this->history)){
            //only check notes if a Google Refine
            
            $uriPattern = self::refineBaseURI;
            
            foreach($BugNotes as $noteObj){
                $noteID = $noteObj->id;
                if(!is_array($this->history)){
                    $note = $noteObj->note;
                    if(stristr($note, $uriPattern)){
                        $link = $this->get_link($note);
                        if($link != false){
                            $history = $this->getHistory($link);
                            if($history != false){
                                $this->get_gRefine_metadata();
                            }
                            $this->history = $history;
                        }
                    }
                    else{
                       //do nothing
                    }
                }
            }
        }
        
    }//end function

    
    function display_history(){
        /*
        Prints history information, if history is an array
        */

        $history = $this->history;
        if(is_array($history)){
            
            if(!$this->projectMeta){
                echo "<h4>Google Refine Edit History [<a href='".$this->projectURI."'>Link</a>]</h4> \n";
            }
            else{
                $meta = $this->projectMeta;
                echo "<h4>Google Refine Edit History [<a href='".$this->projectURI."'>".$meta["name"]."</a>]</h4> \n";
            }
	    
	    $tableMetadataPage = plugin_page( 'data-doc-fields' )."&issue=".$this->bugID."&grProject=".$this->projectID;
	    
	    if($this->bugResolved){
		echo "<p>Review and edit documentation for this dataset. [<a href='".$tableMetadataPage."'>Click here</a>]</p>";
	    }
	    
	    echo "<ol id='gref'> \n";
            
            //show all or just a portion of the edit history
            $showAll = false;
            if(isset($_GET["grDisplay"])){
                if($_GET["grDisplay"] == "all"){
                    $showAll = true;
                }
            }
            
            $sort = false;
            $displayLink = "view.php?id=".$this->bugID."&grSort=recent";
            if($showAll){
                $displayLink .= "&grDisplay=all";
            }
            $displayLink .= "#gref";
            
            $displayOptions =  "<a href='".$displayLink."'>[Sort Recent First]</a>";
            $showMoreLink = "<a href='view.php?id=".$this->bugID."&grDisplay=all#gref'>[Show All Edits]</a>";
            if(isset($_GET["grSort"])){
                $sort = $_GET["grSort"];
                
                $showMoreLink = "<a href='view.php?id=".$this->bugID."&grSort=".$sort."&grDisplay=all#gref'>[Show All Edits]</a>";
                
                if($sort == "recent"){
                    $altHist = array();
                    foreach($history["past"] as $event){
                        $altHist[strtotime($event["time"])] = $event;
                    }
                    
                    krsort($altHist);
                    unset($history["past"]);
                    foreach($altHist as $event){
                        $history["past"][] = $event;
                    }
                    unset($altHist);
                    
                    $displayLink = "view.php?id=".$this->bugID;
                    if($showAll){
                        $displayLink .= "&grDisplay=all";
                    }
                    
                    $displayLink .= "#gref";
                    
                    $displayOptions =  "<a href='".$displayLink."'>[Sort Recent Last]</a>";
                }
            }
            
            
            $i = 0;
            $editNum = count($history["past"]);
            foreach($history["past"] as $event){
                
                if($i < self::maxShow || $showAll){
                    echo "<li>".$event["description"]." (".date("F j, Y, g:i a", strtotime($event["time"])).") </li>\n";
                }
                elseif($i == self::maxShow && !$showAll){
                    echo "<li><em>".($editNum-$i)." more edits, ".$showMoreLink."</em></li>\n";
                }
                else{
                    break;
                }
            
            $i++;
            }
            
            echo "</ol> \n";
            echo $displayOptions;
            echo "<br/> \n";
            echo "<br/> \n";
        }
        
    }//end function

    
    //get metadata for the google refine project
    function get_gRefine_metadata(){
        
        $projectID = $this->projectID;
        
        if(!self::refineLocalURI){
            //connect to Google Refine remotely (too slow if through a reverse proxy server)
            $metadataURI = self::refineBaseURI."/command/core/get-project-metadata?project=".$projectID;
        }
        else{
            //connect to local server Refine
            $metadataURI  = self::refineLocalURI."/command/core/get-project-metadata?project=".$projectID;
        }
        
        @$json = file_get_contents($metadataURI);
        if($json != false){
            $this->projectMeta = json_decode($json, true);
        }
        
    }
    
    
    
    function get_link($note){
        
        $link = false;
        $uriPattern = self::refineBaseURI;
        //$uriPattern = "http://";
        
        $reg_exUrl = "/(http|https)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
            // Check if there is a url in the text
        if (preg_match_all($reg_exUrl, $note, $url)) {
            // check hyper links for the pattern we want
            foreach($url[0] as $actLink){
                if(stristr($actLink, $uriPattern)){
                    $link = $actLink;
                }
            }
            
            if($link != false){
                $linkLen = strlen($link);
                $lastChar = substr($link, $linkLen-1, 1);
                if(!ctype_alnum($lastChar)){
                    $link = substr($link, 0, $linkLen -1 ); //get rid of last character, if not alphanumeric
                }
            }
            
        }
       
        return $link;
    }//end function
    

    function getHistory($link){
        
        /*
        Parse URL, get project ID, get history data from the project from JSON and return as PHP array
        
        Example pattern
        http://refine.opencontext.org/project?project=2104843610664
        */
        $history = false;
        $linkArray = parse_url($link);
        $linkParams = $this->convertUrlQuery($linkArray["query"]);
      
        if(isset($linkParams["project"])){
            $projectID = $linkParams["project"];
            $this->projectID = $projectID;
            $this->projectURI = self::refineBaseURI."/project?project=".$projectID;
            
            if(!self::refineLocalURI){
                //connect to Google Refine remotely (too slow if through a reverse proxy server)
                $historyURI = self::refineBaseURI."/command/core/get-history?project=".$projectID;
            }
            else{
                //connect to local server Refine
                $historyURI = self::refineLocalURI."/command/core/get-history?project=".$projectID;
            }
            
            //echo "<br/><strong>here!! $historyURI </strong>";
            
            @$json = file_get_contents($historyURI);
            if($json != false){
                $history = json_decode($json, true); 
            } 
        }
        
        return $history;
    }//end function

    
    
    function convertUrlQuery($query) { 
        $queryParts = explode('&', $query); 
        
        $params = array(); 
        foreach ($queryParts as $param) { 
            $item = explode('=', $param); 
            $params[$item[0]] = $item[1]; 
        } 
        
        return $params; 
    } 
    


}//end class

?>